//
// Created on 2025/11/10.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#ifndef PRE_EXPORT_TEST_PRE_EXPORT_H
#define PRE_EXPORT_TEST_PRE_EXPORT_H
#include <memory>
#include <shared_mutex>
#include <fstream>
#include <sstream>
#include <rawfile/raw_file.h>
#include <rawfile/raw_file_manager.h>
#include "pre_export/background_cache.h"
#include "pre_export/codec_common.h"
#include <cassert>
#include <thread>

#define CHECK_RETURN_ERROR_IF_FALSE(expr)       \
    do {                                        \
        if (!(expr)) {                          \
            PRE_EXPORT_LOGE("check failed");    \
            return ResultCode::ERROR;           \
        }                                       \
    } while(false)                              \

class PreExportTest {
public:
    PreExportTest(NativeResourceManager *m) {
        mgr_ = m;
    }

    std::string testAllCase() {
        std::stringstream ss;
        ss << "testcase start\n";
        int index = 0;
        for (auto fc: {&PreExportTest::testCase1, &PreExportTest::testCase2,
                       &PreExportTest::testCase3, &PreExportTest::testCase4,
                       &PreExportTest::testCase5}) {
            index += 1;
            auto result = (this->*fc)();
            if (result != ResultCode::OK) {
                ss << "\nTestcase" << index << " failed: " << static_cast<int>(result);
            } else {
                ss << "\nTestcase" << index << " pass: " << static_cast<int>(result);
            }
        }
        return ss.str();
    }
    
    ResultCode testCase1() {
        // 预导入hash1 --> hash1编码完成 --> 导出hash1
        PRE_EXPORT_LOGI("test %{public}s start", __func__);
        // 预导入hash1
        // c1 [0-9] size 10
        uint64_t hash1Start = 0;
        uint64_t hash1End = 9;
        std::shared_ptr<BackgroundCache> c1 = std::make_shared<BackgroundCache>(
            hash1End + 1, codecWidth, codecHeight, codecFrameRate, codecPixelFormat);
        auto code = c1->SetCachePath(cachePath_);
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        code = c1->SetHash("hash1");
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        // 未开始时的检查
        uint64_t frameStart = hash1Start;
        uint64_t frameEnd = hash1End;
        bool b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::PRE_EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == false);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash1Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash1End);
        // 喂全部帧
        putFrameInRange(c1, frameStart, frameEnd, ExportType::PRE_EXPORT);
        // 再次检查至补充完帧
        frameStart = hash1Start;
        frameEnd = hash1End;
        b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::PRE_EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == true);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash1Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash1End);

    
        // 此处模拟编码完成过程
        std::this_thread::sleep_for(std::chrono::seconds(timeout));
        frameStart = hash1Start;
        frameEnd = hash1End;
        b = c1->CheckCachedFrameRange(frameStart, &frameStart, &frameEnd, ExportType::PRE_EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == true);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash1Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash1End);
    
        // 导出
        code = c1->RunUntilEncodeFinished(timeout);
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        std::unique_ptr<std::ofstream> fd = std::make_unique<std::ofstream>();
        std::string outputFile = cachePath_ + "testFinal.h264";
        fd->open(outputFile, std::ios::out | std::ios::binary | std::ios::ate);
        for(uint64_t i = hash1Start; i <= hash1End; i++) {
            void *outFrameData = nullptr;
            uint32_t outFrameSize = 0;
            code = c1->GetFrame(i, &outFrameData, &outFrameSize, ExportType::EXPORT);
            CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
            fd->write(reinterpret_cast<char *>(outFrameData), outFrameSize);
            free(outFrameData);
        }
        fd->close();
        return ResultCode::OK;
    }
    
    ResultCode testCase2() {
        // 导入hash1 --> hash1喂了一半帧/未开始编码 --> 直接导出hash1
        PRE_EXPORT_LOGI("test %{public}s start", __func__);
        // 预导入hash1
        // c1 [0-9] size 10
        uint64_t hash1Start = 0;
        uint64_t hash1End = 9;
        std::shared_ptr<BackgroundCache> c1 = std::make_shared<BackgroundCache>(
            hash1End + 1, codecWidth, codecHeight, codecFrameRate, codecPixelFormat);
        auto code = c1->SetCachePath(cachePath_);
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        code = c1->SetHash("hash1");
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        // 未开始时的检查
        uint64_t frameStart = hash1Start;
        uint64_t frameEnd = hash1End;
        bool b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::PRE_EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == false);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash1Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash1End);
        // 只喂了一半帧 [0 - 4]
        uint64_t partEnd = 4;
        putFrameInRange(c1, frameStart, partEnd, ExportType::PRE_EXPORT);
    
        // 直接导出
        // 检查范围，重新喂帧
        frameStart = hash1Start;
        frameEnd = hash1End;
        b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == true);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash1Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == partEnd);
        frameStart = hash1Start;
        frameEnd = hash1End;
        b = c1->CheckFrameRange(partEnd + 1, &frameStart, &frameEnd, ExportType::EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == false);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == partEnd + 1);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash1End);
        putFrameInRange(c1, frameStart, frameEnd, ExportType::EXPORT);
        // 再次检查至补充完帧
        frameStart = hash1Start;
        frameEnd = hash1End;
        b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::PRE_EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == true);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash1Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash1End);
    
        code = c1->RunUntilEncodeFinished(timeout);
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        std::unique_ptr<std::ofstream> fd = std::make_unique<std::ofstream>();
        std::string outputFile = cachePath_ + "testFinal.h264";
        fd->open(outputFile, std::ios::out | std::ios::binary | std::ios::ate);
        for(uint64_t i = hash1Start; i <= hash1End; i++) {
            void *outFrameData = nullptr;
            uint32_t outFrameSize = 0;
            code = c1->GetFrame(i, &outFrameData, &outFrameSize, ExportType::EXPORT);
            CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
            fd->write(reinterpret_cast<char *>(outFrameData), outFrameSize);
            free(outFrameData);
        }
        fd->close();
        return ResultCode::OK;
    }
    
    ResultCode testCase3() {
        // 导入hash1 --> hash1喂全部 --> 中断 --> 检查并预编码完成 --> 直接导出hash1
        PRE_EXPORT_LOGI("test %{public}s start", __func__);
        // 预导入hash1
        // c1 [0-9] size 10
        uint64_t hash1Start = 0;
        uint64_t hash1End = 9;
        std::shared_ptr<BackgroundCache> c1 = std::make_shared<BackgroundCache>(
            hash1End + 1, codecWidth, codecHeight, codecFrameRate, codecPixelFormat);
        auto code = c1->SetCachePath(cachePath_);
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        code = c1->SetHash("hash1");
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        // 未开始时的检查
        uint64_t frameStart = hash1Start;
        uint64_t frameEnd = hash1End;
        bool b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::PRE_EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == false);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash1Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash1End);
        // 提供全部帧
        putFrameInRange(c1, frameStart, frameEnd, ExportType::PRE_EXPORT);
        // 再次检查至补充完帧
        frameStart = hash1Start;
        frameEnd = hash1End;
        b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::PRE_EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == true);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash1Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash1End);
    
        // 中断
        // interrupt and resume
        c1->NotifyInterrupt();
        CHECK_RETURN_ERROR_IF_FALSE(c1->IsInterrupt() == true);
        // 模拟未完成编码过程
        std::this_thread::sleep_for(std::chrono::seconds(timeout));
        b = c1->CheckCachedFrameRange(frameStart, &frameStart, &frameEnd, ExportType::PRE_EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart != hash1Start || frameEnd != hash1End);
        // 重新检查是否补帧并恢复编码
        frameStart = hash1Start;
        frameEnd = hash1End;
        b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::PRE_EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == true);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash1Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash1End);
        // 模拟编码完成过程
        std::this_thread::sleep_for(std::chrono::seconds(timeout));
        frameStart = hash1Start;
        frameEnd = hash1End;
        b = c1->CheckCachedFrameRange(frameStart, &frameStart, &frameEnd, ExportType::PRE_EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == true);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash1Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash1End);

        // 直接导出
        code = c1->RunUntilEncodeFinished(timeout);
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        std::unique_ptr<std::ofstream> fd = std::make_unique<std::ofstream>();
        std::string outputFile = cachePath_ + "testFinal.h264";
        fd->open(outputFile, std::ios::out | std::ios::binary | std::ios::ate);
        for(uint64_t i = hash1Start; i <= hash1End; i++) {
            void *outFrameData = nullptr;
            uint32_t outFrameSize = 0;
            code = c1->GetFrame(i, &outFrameData, &outFrameSize, ExportType::EXPORT);
            CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
            fd->write(reinterpret_cast<char *>(outFrameData), outFrameSize);
            free(outFrameData);
        }
        fd->close();
        return ResultCode::OK;
    }
    
    ResultCode testCase4() {
        // 导入hash1 --> hash1预编码完成 --> 导入hash2[hash1中段的部分覆盖] --> 检查并预编码完成 --> 直接导出hash1 hash2
        PRE_EXPORT_LOGI("test %{public}s start", __func__);
        // 预导入hash1
        // c1 [0-9] size 10
        uint64_t hash1Start = 0;
        uint64_t hash1End = 9;
        std::shared_ptr<BackgroundCache> c1 = std::make_shared<BackgroundCache>(
            hash1End + 1, codecWidth, codecHeight, codecFrameRate, codecPixelFormat);
        auto code = c1->SetCachePath(cachePath_);
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        code = c1->SetHash("hash1");
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        // 未开始时的检查
        uint64_t frameStart = hash1Start;
        uint64_t frameEnd = hash1End;
        bool b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::PRE_EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == false);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash1Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash1End);
        // 提供全部帧
        putFrameInRange(c1, frameStart, frameEnd, ExportType::PRE_EXPORT);
        // 再次检查至补充完帧
        frameStart = hash1Start;
        frameEnd = hash1End;
        b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::PRE_EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == true);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash1Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash1End);
        // 模拟hash1预编码完成过程
        std::this_thread::sleep_for(std::chrono::seconds(timeout));
        frameStart = hash1Start;
        frameEnd = hash1End;
        b = c1->CheckCachedFrameRange(frameStart, &frameStart, &frameEnd, ExportType::PRE_EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == true);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash1Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash1End);
    
        // 预导入hash2
        // c2 [0-3] size 4 偏移量 4 映射 [4, 7]
        uint64_t hash2Start = 0;
        uint64_t hash2End = 3;
        uint64_t offset = 4;
        std::shared_ptr<BackgroundCache> c2 = std::make_shared<BackgroundCache>(
            hash2End + 1, codecWidth, codecHeight, codecFrameRate, codecPixelFormat);
        code = c2->SetCachePath(cachePath_);
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        code = c2->SetHash("hash2");
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        // 未开始时的检查
        frameStart = hash2Start;
        frameEnd = hash2End;
        b = c2->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::PRE_EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == false);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash2Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash2End);
        // 提供全部帧
        putFrameInRange(c2, frameStart, frameEnd, ExportType::PRE_EXPORT, offset);
        // 再次检查至补充完帧
        frameStart = hash2Start;
        frameEnd = hash2End;
        b = c2->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::PRE_EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == true);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash2Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash2End);
    
        // 模拟hash2预编码完成过程
        std::this_thread::sleep_for(std::chrono::seconds(timeout));
        frameStart = hash2Start;
        frameEnd = hash2End;
        b = c2->CheckCachedFrameRange(frameStart, &frameStart, &frameEnd, ExportType::PRE_EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == true);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash2Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash2End);
    
        // 导出hash1[0, 3] hash2[4,7] hash3[8, 9]
        // 检查是否需要补充帧 
        // 0 - 3 --> 0~2, 3 重新编码3
        frameStart = hash1Start;
        frameEnd = hash2Start + offset - 1;
        b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == true);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash1Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == 2);
        // 提供需重新编码的帧
        frameStart = 3;
        frameEnd = hash2Start + offset - 1;
        b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == false);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == 3);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash2Start + offset - 1);
        putFrameInRange(c1, frameStart, frameEnd, ExportType::EXPORT);
        // 再次检查至补充完帧
        frameStart = 3;
        frameEnd = hash2Start + offset - 1;
        b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == true);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == 3);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash2Start + offset - 1);
        // 8 - 9 --> 0~2, 3~5, 6~8, 9  重新编译8
        frameStart = hash2End + offset + 1;
        frameEnd = hash1End;
        b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == false);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash2End + offset + 1);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash2End + offset + 1);
        // 提供需重新编码的帧
        putFrameInRange(c1, frameStart, frameEnd, ExportType::EXPORT);
        // 再次检查至补充完帧
        frameStart = hash2End + offset + 1;
        frameEnd = hash1End;
        b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == true);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash2End + offset + 1);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash1End);
    
        // 导出帧
        code = c1->RunUntilEncodeFinished(timeout);
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        std::unique_ptr<std::ofstream> fd = std::make_unique<std::ofstream>();
        std::string outputFile = cachePath_ + "testFinal.h264";
        fd->open(outputFile, std::ios::out | std::ios::binary | std::ios::ate);
        for(uint64_t i = hash1Start; i < offset; i++) {
            void *outFrameData = nullptr;
            uint32_t outFrameSize = 0;
            code = c1->GetFrame(i, &outFrameData, &outFrameSize, ExportType::EXPORT);
            CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
            fd->write(reinterpret_cast<char *>(outFrameData), outFrameSize);
            free(outFrameData);
        }
        code = c2->RunUntilEncodeFinished(timeout);
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        for(uint64_t i = hash2Start; i <= hash2End; i++) {
            void *outFrameData = nullptr;
            uint32_t outFrameSize = 0;
            code = c2->GetFrame(i, &outFrameData, &outFrameSize, ExportType::EXPORT);
            CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
            fd->write(reinterpret_cast<char *>(outFrameData), outFrameSize);
            free(outFrameData);
        }
        for(uint64_t i = offset + hash2End + 1; i <= hash1End; i++) {
            void *outFrameData = nullptr;
            uint32_t outFrameSize = 0;
            code = c1->GetFrame(i, &outFrameData, &outFrameSize, ExportType::EXPORT);
            CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
            fd->write(reinterpret_cast<char *>(outFrameData), outFrameSize);
            free(outFrameData);
        }       
        fd->close();
        return ResultCode::OK;
    }
    
    ResultCode testCase5() {
        // 导入hash1 --> 导入hash2[hash1中段的部分覆盖] --> 直接导出hash1 hash2
        PRE_EXPORT_LOGI("test %{public}s start", __func__);
        // 预导入hash1
        // c1 [0-9] size 10
        uint64_t hash1Start = 0;
        uint64_t hash1End = 9;
        std::shared_ptr<BackgroundCache> c1 = std::make_shared<BackgroundCache>(
            hash1End + 1, codecWidth, codecHeight, codecFrameRate, codecPixelFormat);
        auto code = c1->SetCachePath(cachePath_);
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        code = c1->SetHash("hash1");
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        
        // 预导入hash2
        // c1 [0-3] size 4 偏移量 4 映射 [4, 7]
        uint64_t hash2Start = 0;
        uint64_t hash2End = 3;
        uint64_t offset = 4;
        std::shared_ptr<BackgroundCache> c2 = std::make_shared<BackgroundCache>(
            hash2End + 1, codecWidth, codecHeight, codecFrameRate, codecPixelFormat);
        code = c2->SetCachePath(cachePath_);
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        code = c2->SetHash("hash2");
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
    
        // 直接导出hash1[0, 3] hash2[4,7] hash3[8, 9]
        // 检查是否需要补充帧 
        // hash1 0-3
        uint64_t frameStart = hash1Start;
        uint64_t frameEnd = hash2Start + offset - 1;
        auto b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == false);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash1Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash2Start + offset - 1);
        putFrameInRange(c1, frameStart, frameEnd, ExportType::EXPORT);
        // 再次检查至补充完帧
        frameStart = hash1Start;
        frameEnd = hash2Start + offset - 1;
        b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == true);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash1Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash2Start + offset - 1);
        // hash2 4-7
        frameStart = hash2Start;
        frameEnd = hash2End;
        b = c2->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == false);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash2Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash2End);
        // 提供全部帧
        putFrameInRange(c2, frameStart, frameEnd, ExportType::EXPORT, offset);
        // 再次检查至补充完帧
        frameStart = hash2Start;
        frameEnd = hash2End;
        b = c2->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == true);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash2Start);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash2End);
        // hash1 8 - 9
        frameStart = hash2End + offset + 1;
        frameEnd = hash1End;
        b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == false);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash2End + offset + 1);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash1End);
        // 提供需重新编码的帧
        putFrameInRange(c1, frameStart, frameEnd, ExportType::EXPORT);
        // 再次检查至补充完帧
        frameStart = hash2End + offset + 1;
        frameEnd = hash1End;
        b = c1->CheckFrameRange(frameStart, &frameStart, &frameEnd, ExportType::EXPORT);
        CHECK_RETURN_ERROR_IF_FALSE(b == true);
        CHECK_RETURN_ERROR_IF_FALSE(frameStart == hash2End + offset + 1);
        CHECK_RETURN_ERROR_IF_FALSE(frameEnd == hash1End);
    
        // 导出帧
        code = c1->RunUntilEncodeFinished(timeout);
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        std::unique_ptr<std::ofstream> fd = std::make_unique<std::ofstream>();
        std::string outputFile = cachePath_ + "testFinal.h264";
        fd->open(outputFile, std::ios::out | std::ios::binary | std::ios::ate);
        for(uint64_t i = hash1Start; i < offset; i++) {
            void *outFrameData = nullptr;
            uint32_t outFrameSize = 0;
            code = c1->GetFrame(i, &outFrameData, &outFrameSize, ExportType::EXPORT);
            CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
            fd->write(reinterpret_cast<char *>(outFrameData), outFrameSize);
            free(outFrameData);
        }
        code = c2->RunUntilEncodeFinished(timeout);
        CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
        for(uint64_t i = hash2Start; i <= hash2End; i++) {
            void *outFrameData = nullptr;
            uint32_t outFrameSize = 0;
            code = c2->GetFrame(i, &outFrameData, &outFrameSize, ExportType::EXPORT);
            CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
            fd->write(reinterpret_cast<char *>(outFrameData), outFrameSize);
            free(outFrameData);
        }
        code = c1->RunUntilEncodeFinished(timeout);
        for(uint64_t i = offset + hash2End + 1; i <= hash1End; i++) {
            void *outFrameData = nullptr;
            uint32_t outFrameSize = 0;
            code = c1->GetFrame(i, &outFrameData, &outFrameSize, ExportType::EXPORT);
            CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
            fd->write(reinterpret_cast<char *>(outFrameData), outFrameSize);
            free(outFrameData);
        }       
        fd->close();
        return ResultCode::OK;
    }
    
    ResultCode readRawFile(std::string path, void **data, uint64_t *size) {
        CHECK_RETURN_ERROR_IF_FALSE(mgr_ != nullptr);
        RawFile *descriptor = OH_ResourceManager_OpenRawFile(mgr_, path.c_str());
        CHECK_RETURN_ERROR_IF_FALSE(descriptor != nullptr);
        long bufSize = OH_ResourceManager_GetRawFileSize(descriptor);
        char *buf = (char *)malloc(bufSize);
        if (buf == NULL) {
            OH_ResourceManager_CloseRawFile(descriptor);
            return ResultCode::SYSTEM_ERROR;
        }
        long readSize = OH_ResourceManager_ReadRawFile(descriptor, buf, bufSize);
        if (readSize < 1) {
            free(buf);
            OH_ResourceManager_CloseRawFile(descriptor);
            return ResultCode::SYSTEM_ERROR;
        }
        *data = buf;
        *size = bufSize;
        OH_ResourceManager_CloseRawFile(descriptor);
        return ResultCode::OK;
    }
    
    ResultCode putFrameInRange(std::shared_ptr<BackgroundCache> c, uint64_t frameStart, uint64_t frameEnd,
                               ExportType exportType, uint64_t offset = 0)
    {
        for(uint64_t i = frameStart; i <= frameEnd; i++) {
            void *inFrameData = nullptr;
            uint64_t size = 0;
            auto code = readRawFile("files" + std::to_string(i + offset) + ".yuv",  &inFrameData, &size);
            CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
            CHECK_RETURN_ERROR_IF_FALSE(inFrameData != nullptr);
            CHECK_RETURN_ERROR_IF_FALSE(size == frameWidth * frameHeight);
            code = c->PutFrame(i, inFrameData, frameWidth, frameHeight, frameWidth, exportType);
            CHECK_RETURN_ERROR_IF_FALSE(code == ResultCode::OK);
            if (inFrameData != nullptr) {
                free(inFrameData);
                inFrameData = nullptr;
            }
        }
        return ResultCode::OK;
    }
    
private:
    NativeResourceManager *mgr_;
    uint32_t frameWidth = 3120;
    uint32_t frameHeight = 3136;
    uint32_t codecWidth = 3120;
    uint32_t codecHeight = 2080; 
    // uint32_t codecFrameRate = 60;
    uint32_t codecFrameRate = 3;
    OH_AVPixelFormat codecPixelFormat = AV_PIXEL_FORMAT_NV12;
    // /data/app/el2/100/base/com.example.pre_export/temp/
    std::string cachePath_ = "/data/storage/el2/base/temp/";
    std::uint64_t timeout = 10;
};

#endif //PRE_EXPORT_TEST_PRE_EXPORT_H
